/*
 * Copyright 2010 Michael Nitsche
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package de.mnit.basis.swt.element.steuer.rollbar.gruppe.tabelle;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.ToolTip;

import de.mnit.basis.daten.WandleArray;
import de.mnit.basis.daten.konstant.sys.SYSTEM;
import de.mnit.basis.daten.struktur.S_Folge;
import de.mnit.basis.daten.struktur.gruppe.Gruppe2;
import de.mnit.basis.daten.struktur.liste.Liste;
import de.mnit.basis.daten.struktur.liste.S_Liste;
import de.mnit.basis.daten.struktur.ordnen.Sortieren;
import de.mnit.basis.daten.struktur.tabelle.S_Tabelle;
import de.mnit.basis.daten.struktur.tabelle.Tabelle;
import de.mnit.basis.fehler.Fehler;
import de.mnit.basis.swt.element.feld.SWT_TabellenSpalte;
import de.mnit.basis.sys.Ausgabe;
import de.mnit.basis.sys.event.S_Zuhoerer;

public class SWT_TabelleVirtuell extends A_SWT_Tabelle<SWT_TabelleVirtuell> {

	public static void main(String[] args) {
		start(new SWT_TabelleVirtuell(),800,600);
	}


	private S_Tabelle<?> inhalt;
	private Listener listener, tick_listener;
	private int tip_spalte=0;
	private int tick_spalte=0;
	private S_Sortiermodul sortierer;
	private Integer letzte_spalte_auto_min=null;


	// FUNKTION

	/**
	 * Geht natürlich nur, wenn die Auswahl von mehreren Einträgen möglich ist!
	 */
	public void sAuswahlAlles() {
		t.swt().selectAll();
	}

	@SuppressWarnings("unchecked")
	public void sFeld(int spalte, int zeile, Object objekt) {
		((S_Tabelle<Object>)this.inhalt).setze(spalte, zeile, objekt);
		swt().clearAll();
	}

	public void sInhalt(S_Tabelle<?> tabelle) {
		Fehler.objekt.wenn_Null(tabelle);
		Fehler.bool.wenn_Nicht(this.istErzeugt());
		this.inhalt=tabelle;
		Fehler.zahl.wenn_ZuKlein(swt().getColumnCount(),tabelle.gBreite());
		if(this.listener!=null)
			swt().removeListener(SWT.SetData,this.listener);
		swt().setItemCount(0);

		this.listener=new Listener() {
			public void handleEvent (Event event) {
//				if(inhalt==null)
//					return;
				TableItem item = (TableItem) event.item;
				int index = swt().indexOf(item);
				for(int spalte=0; spalte<swt().getColumnCount(); spalte++)
					item.setText(spalte,""+inhalt.gSpalte(spalte+1).gib(index+1));
				if(tick_spalte!=0)
					item.setChecked((inhalt.gSpalte(tick_spalte).gib(index+1)+"").equals("true"));
			}
		};
		swt().addListener(SWT.SetData,this.listener);
		swt().setItemCount(tabelle.gLaenge());
	}

	public void sortieren(int spalte, boolean absteigend) {
		this.sortieren(spalte,absteigend,spalte);
	}

	public void sortieren(int spalte, boolean absteigend, int nach) {
		if(this.inhalt==null || this.inhalt.gLaenge()==0)
			return;
		this.sortierer.sortieren(nach, absteigend, this.inhalt);
        swt().setSortColumn(swt().getColumn(spalte-1)); // Bei Fehler liegt die Spalte wohl nicht im sichtbaren Bereich!
        swt().setSortDirection(absteigend ? SWT.DOWN : SWT.UP);
		swt().clearAll();
	}

	public void bauen(boolean sortierbar, boolean verschiebbar, S_Tabelle<?> tabelle) {
		String[] titel=WandleArray.zuStringArray(tabelle.gZeile(1).zuBereich());
		this.bauen(sortierbar,verschiebbar,titel);
		tabelle.minus(1);
		this.sInhalt(tabelle);
		if(sortierbar)
			this.sortieren(1,false);
	}

	public void sTip(int spalte) {
		Fehler.zahl.wenn_ZuKlein(1,spalte);
		if(this.tip_spalte==0) {
			final Listener tip=new Listener(){
				ToolTip tip=new ToolTip(((Table)t.swt()).getShell(),SWT.NONE);

				public void handleEvent(Event event) {
					if(tip.isDisposed()) return;
					if(event.type==SWT.MouseHover) {
						TableItem item = swt().getItem(new Point (event.x, event.y));
						if(item != null) {
							tip.setMessage(""+inhalt.gSpalte(tip_spalte).gib(swt().indexOf(item)+1));
							Rectangle rect = item.getBounds(0);
							Point pt = swt().toDisplay(rect.x, rect.y);
							tip.setLocation(pt.x,pt.y);
							tip.setVisible(true);
						}
					}
					else tip.setVisible(false);
				}
			};
			swt().addListener(SWT.Dispose,   tip);
			swt().addListener(SWT.KeyDown,   tip);
			swt().addListener(SWT.MouseMove, tip);
			swt().addListener(SWT.MouseHover,tip);
		}
		this.tip_spalte=spalte;
	}

	public void sLetzteSpalteAuto(final int minimal) {
		Fehler.bool.wenn(this.letzte_spalte_auto_min!=null); // Wurde bereits gesetzt!
		Fehler.zahl.wenn_ZuGross(0, this.swt().getColumns().length); // Es sind bereits Spalten vorhanden
		this.letzte_spalte_auto_min=minimal;
		if(!SYSTEM.gAktuell().istWindows()) //Dieser Fehler ist bis jetzt nur in Windows bekannt
			return;

		this.swt().addControlListener(new ControlListener(){
			private boolean single=false;
			public void controlMoved(ControlEvent e) {}
			public void controlResized(ControlEvent e) {
				if(single) { //BUGFIX: Bei column.setWidth wird ein Resized ausgelöst!
					single=false;
					return;
				}
				iLetzteSpalteAnpassen(minimal);
				single=true;
			}
		});
	}

	public SWT_TabellenSpalte nTabellenSpalte(String text) {
		SWT_TabellenSpalte spalte=super.nTabellenSpalte(text);
		if(this.letzte_spalte_auto_min!=null)
			spalte.swt().addControlListener(new ControlListener(){
				public void controlMoved(ControlEvent e) {
					iLetzteSpalteAnpassen(letzte_spalte_auto_min);
				}
				public void controlResized(ControlEvent e) {
				}
			});
		return spalte;
	}

	public void letzteSpalteAnpassen() {
		if(!SYSTEM.gAktuell().istWindows()) //Dieser Fehler ist bis jetzt nur von Win bekannt
			return;
		Fehler.objekt.wenn_Null(t.letzte_spalte_auto_min);
		iLetzteSpalteAnpassen(t.letzte_spalte_auto_min);
	}

	private void iLetzteSpalteAnpassen(int minimal) {
		Table t=this.swt();
		Rectangle groesse = t.getClientArea();
		int width = groesse.width - 2 * t.getBorderWidth();

		TableColumn[] spalten = t.getColumns();
		for(int i=0; i<spalten.length-1; i++)
			width -= spalten[i].getWidth();

		width=Math.max(minimal, width);
		spalten[spalten.length-1].setWidth(width);
	}

	public void sTickSpalte(final int spalte) {
		this.tick_spalte=spalte;
		if(this.tick_listener!=null)
			t.swt().removeListener(SWT.Selection, this.tick_listener);
		if(this.tick_spalte>0) {
			Listener l=new Listener(){
				@SuppressWarnings("unchecked")
				public void handleEvent(Event event) {
//					Vorherige Lösung, nur, egal wo man hinklickt, event.index+1 ist immer 1!!!
//					((S_Tabelle<Object>)inhalt).setze(tick_spalte, event.index+1, ""+gTickAuswahl(event.index+1));
					Integer zeile=t.gZeilenNr(event);
					if(zeile==null)
						return;
					boolean auswahl=t.gTickAuswahl(zeile);
					((S_Tabelle<String>)t.gInhalt()).setze(spalte, zeile, ""+auswahl);
				}
			};
			this.tick_listener=l;
			this.eAuswahl(l);
		}
	}

	public void sSortierer(S_Sortiermodul s) {
		this.sortierer=s;
	}

	// LESEN

	public S_Tabelle<?> gInhalt() {
		return this.inhalt;
	}

	public S_Tabelle<Object> gAuswahl() {
		if(this.inhalt==null) return null;
		S_Tabelle<Object> erg=Tabelle.neu(this.inhalt.gBreite());
		for(int i : this.gAuswahlIndex()) erg.plus(this.inhalt.gZeile(i));
		return erg;
	}

	public int gSortierspalte() {
		TableColumn tc=swt().getSortColumn();
		if(tc==null) return -1;
		return t.gSpalte(swt().indexOf(tc)+1).gSortierspalte();
	}

	public boolean gSortiertAbsteigend()   { return swt().getSortDirection()==SWT.DOWN; }

	/** @deprecated **/ //gZeilenNrBeiAbsPos verwenden
	public Object[] gZeileBeiAbsPos(int x, int y) {
		Point r=this.swt().toDisplay(0,0);
		TableItem ti=swt().getItem(new Point(x-r.x,y-r.y));
		if(ti==null)
			Ausgabe.debug("ist null",x,y,r.x,r.y);
		return this.inhalt.gZeile(gZeilenNr(ti)).zuBereich();
	}

	public S_Folge<Object> gTickAuswahlSpalte(int spalte) {
		S_Liste<Object> auswahl=Liste.neu();
		for(int z=1; z<=this.gLaenge(); z++)
			if(this.gTickAuswahl(z))
				auswahl.plus(t.gInhalt().gib(spalte, z));
		return auswahl;
	}

	// EVENT

	public void eFeldNeu(Listener l) {
		swt().addListener(SWT.SetData,l);
	}

	public void eFeldZeichnen(final int spalte, final S_Zuhoerer<Gruppe2<Event,Object[]>> aktion) {
		this.swt().addListener(SWT.PaintItem, new Listener(){
			public void handleEvent(Event event) {
				if(event.index+1==spalte)
					aktion.verarbeite(
						Gruppe2.neu(
							event,
							t.gInhalt().gZeile(t.gZeilenNr((TableItem)event.item)).zuBereich()
					));
			}
		});
	}

	// ERZEUGEN

	protected int style6() {
		return SWT.VIRTUAL;
	}

	protected void init5() {
		super.init5();

		this.sortierer=new S_Sortiermodul(){
			public void sortieren(int spalte, boolean ab_n_auf, S_Tabelle<?> tabelle) {
				Sortieren.sortieren(t.inhalt, new int[]{ab_n_auf ? 0-spalte : spalte});
			}
		};
	}

}
